package com.hzy.admin.services.system.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzy.admin.models.vo.system.SysRoleMenuFunctionTreeVo;
import com.hzy.admin.models.vo.system.SysRoleMenuFunctionVo;
import com.hzy.admin.services.system.ISysFunctionService;
import com.hzy.admin.services.system.ISysMenuFunctionService;
import com.hzy.admin.services.system.ISysMenuService;
import com.hzy.admin.services.system.ISysRoleMenuFunctionService;
import com.hzy.admin.repository.entity.system.SysFunction;
import com.hzy.admin.repository.entity.system.SysMenu;
import com.hzy.admin.repository.entity.system.SysMenuFunction;
import com.hzy.admin.repository.entity.system.SysRoleMenuFunction;
import com.hzy.admin.repository.mapper.system.ISysRoleMenuFunctionMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author HZY
 * @since 2020-04-29
 */
@Service
public class SysRoleMenuFunctionServiceImpl extends ServiceImpl<ISysRoleMenuFunctionMapper, SysRoleMenuFunction>
        implements ISysRoleMenuFunctionService {
    private final ISysMenuService menuService;
    private final ISysFunctionService functionService;
    private final ISysMenuFunctionService menuFunctionService;

    public SysRoleMenuFunctionServiceImpl(ISysMenuService menuService, ISysFunctionService functionService,
                                          ISysMenuFunctionService menuFunctionService) {
        this.menuService = menuService;
        this.functionService = functionService;
        this.menuFunctionService = menuFunctionService;
    }

    @Override
    @Transactional
    public String saveForm(SysRoleMenuFunctionVo form) {
        String roleId = form.getRoleId();
        String menuId = form.getMenuId();
        List<String> functionIds = form.getFunctionIds();

        this.remove(new LambdaQueryWrapper<SysRoleMenuFunction>().eq(SysRoleMenuFunction::getRoleId, roleId)
                .eq(SysRoleMenuFunction::getMenuId, menuId));

        for (String id : functionIds) {
            SysRoleMenuFunction model = new SysRoleMenuFunction();
            model.setFunctionId(id);
            model.setMenuId(menuId);
            model.setRoleId(roleId);
            this.saveOrUpdate(model);
        }

        return roleId;
    }

    @Override
    public SysRoleMenuFunctionTreeVo getRoleMenuFunctionTree(String roleId) {
        List<SysMenu> menus = this.menuService.lambdaQuery().orderByAsc(SysMenu::getNumber).list();
        List<SysFunction> functions = this.functionService.lambdaQuery().orderByAsc(SysFunction::getNumber).list();
        List<SysMenuFunction> menuFunctions = this.menuFunctionService.lambdaQuery().orderByAsc(SysMenuFunction::getCreateTime).list();
        List<SysRoleMenuFunction> roleMenuFunctions = this.lambdaQuery().eq(SysRoleMenuFunction::getRoleId, roleId).list();

        SysRoleMenuFunctionTreeVo sysRoleMenuFunction = new SysRoleMenuFunctionTreeVo();

        sysRoleMenuFunction.setList(this.createRoleMenuFunctionTree(null, menus, functions, menuFunctions,
                roleMenuFunctions, sysRoleMenuFunction));

        return sysRoleMenuFunction;
    }

    private List<Map<String, Object>> createRoleMenuFunctionTree(String id, List<SysMenu> menuList,
                                                                 List<SysFunction> functionList, List<SysMenuFunction> menuFunctionList,
                                                                 List<SysRoleMenuFunction> roleMenuFunctionList, SysRoleMenuFunctionTreeVo sysRoleMenuFunctionBo) {
        List<Map<String, Object>> menus = new ArrayList<>();
        List<SysMenu> menuItems;
        if (ObjectUtils.isEmpty(id)) {
            menuItems = menuList.stream().filter(w -> ObjectUtils.isEmpty(w.getParentId()))
                    .collect(Collectors.toList());
        } else {
            menuItems = menuList.stream().filter(w -> id.equals(w.getParentId())).collect(Collectors.toList());
        }

        List<Map<String, Object>> children;
        List<Map<String, Object>> functions;
        List<String> checkFunction;

        for (SysMenu sysMenu : menuItems) {
            children = new ArrayList<>();
            functions = new ArrayList<>();
            checkFunction = new ArrayList<>();
            if (menuList.stream().anyMatch(w -> sysMenu.getId().equals(w.getParentId()))) {
                children = this.createRoleMenuFunctionTree(sysMenu.getId(), menuList, functionList, menuFunctionList,
                        roleMenuFunctionList, sysRoleMenuFunctionBo);
            } else {
                for (SysFunction function : functionList) {
                    String functionId = function.getId();
                    boolean menuFunctionAny = menuFunctionList.stream().anyMatch(w -> w.getMenuId().equals(sysMenu.getId()) && w.getFunctionId().equals(functionId));
                    if (!menuFunctionAny) {
                        continue;
                    }
                    Map<String, Object> functionModel = new HashMap<>(2);
                    functionModel.put("id", functionId);
                    functionModel.put("label", function.getName());
                    functions.add(functionModel);

                    boolean roleMenuFunctionAny = roleMenuFunctionList.stream().anyMatch(w -> w.getMenuId().equals(sysMenu.getId()) && w.getFunctionId().equals(function.getId()));
                    if (roleMenuFunctionAny) {
                        checkFunction.add(functionId);
                    }
                }
            }
            if (children.size() > 0) {
                sysRoleMenuFunctionBo.getExpandedRowKeys().add(sysMenu.getId());
            }
            Map<String, Object> map = new HashMap<>(5);
            map.put("id", sysMenu.getId());
            map.put("label", sysMenu.getName() + "-" + sysMenu.getNumber());
            map.put("children", children.size() == 0 ? null : children);
            map.put("functions", functions);
            map.put("checkFunction", checkFunction);
            map.put("checkAll", false);
            menus.add(map);
        }

        return menus;
    }

}
